運用を自動化! CloudWatch と Systems Manager オートメーションでプロセス監視&自動復旧をやってみた
こんにちは。テクニカルサポートチームのShiinaです。
はじめに
CloudWatch で EC2 のプロセス監視を行っていると、アラーム検知時にサービスを再起動させるといった復旧対応の運用を自動化できたらいいなと思いませんか?
今回は CloudWatch アラームの状態変化イベントに基づき、 EventBridge ルールで Systems Manager のオートメーションを実行してサービスを自動復旧させる簡易的な仕組みを実装してみました。
オートメーションを利用して復旧処理を行うため、Lambda 関数の実装は不要です。
概要
CloudWatch エージェントを利用して、プロセス数の閾値をモニタリングする CloudWatch アラームを作成します。
EventBridge ルールを利用して、CloudWatch アラームの状態変化イベント発生時に Systems Manager オートメーションを実行します。
オートメーションでは AWS-RunShellScript を利用し、 systemctl コマンドによるサービス起動で自動復旧を試みます。
前提
- Systems Manager エージェントがインストールされていること
- マネージドインスタンスであり、オートメーションの実行が可能であること
- CloudWatch エージェントがインストールされていること
- プロセス監視には procstat プラグインの pattern を利用します
- プロセス復旧には systemctl コマンドを利用します
設定の流れ
はじめに、EventBridge イベントに基づくオートメーションの実行に必要なロールと、オートメーション用のサービスロールの設定を行います。
次に Systems Manager オートメーションドキュメントを作成します。
その後、CloudWatch エージェントとアラームの設定を行なった上で、オートメーションをターゲットとする EventBridge ルールの作成を実施します。
設定手順
1.IAMロール設定
サービスの呼び出しに必要なロールを2つ設定します。
EventBridge イベント用オートメーション実行ロール、 オートメーション用サービスロールを作成します。
EventBridge イベント用オートメーション実行ロール
-
ロール名
Invoke-Automation-Execution-Role -
許可
下記のインラインポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ActionForSSMAutomation",
"Action": "ssm:StartAutomationExecution",
"Effect": "Allow",
"Resource": [
"*"
]
}
]
}
- 信頼関係
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "TrustEventBridgeService",
"Effect": "Allow",
"Principal": {
"Service": [
"ssm.amazonaws.com",
"events.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
オートメーション用サービスロール
-
ロール名
Automation-Execute-Role -
許可
AmazonSSMAutomationRole
下記のインラインポリシー(arn はご自身のAWSアカウント ID に修正ください)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::XXXXXXXXXXX:role/Automation-Execute-Role"
}
]
}
- 信頼関係
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ssm.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
2.オートメーションドキュメント作成
Systems Manager ドキュメントよりドキュメントの作成メニューよりオートメーションをクリックします。
名前フィールドに ServiceAutoRecoveryAutomation(任意の名前)を入力し、コードタブをクリックします。
下記コードをコピーしてペーストし、ランブックを作成をクリックします。
assumeRole の arn はご自身の環境のオートメーション用サービスロールに修正してください。
schemaVersion: '0.3'
description: This book that automatically recovers services triggered by CloudWatch alarm state changes.
parameters:
pattern:
type: String
description: Target Service Name.
InstanceId:
type: StringList
description: Target InstanceId.
assumeRole: arn:aws:iam::XXXXXXXXXXX:role/Automation-Execute-Role
mainSteps:
- name: CheckAndStartService
action: aws:runCommand
isEnd: true
inputs:
DocumentName: AWS-RunShellScript
Parameters:
commands:
- '#!/bin/bash'
- SERVICE_NAME="{{ pattern }}"
- '# Check the status of the service'
- if systemctl is-active --quiet "$SERVICE_NAME"; then
- ' echo "$SERVICE_NAME is already running."'
- else
- ' echo "$SERVICE_NAME is stopped. Starting it..."'
- ' systemctl start "$SERVICE_NAME"'
- ' # Recheck the status after starting'
- ' if systemctl is-active --quiet "$SERVICE_NAME"; then'
- ' echo "Successfully started service $SERVICE_NAME."'
- ' else'
- ' echo "Failed to start service $SERVICE_NAME."'
- ' exit 1'
- ' fi'
- fi
InstanceIds: '{{ InstanceId }}'
3.CloudWatch エージェントの設定
procstat プラグインの pattern でプロセス監視を行う設定を行います。
cd /opt/aws/amazon-cloudwatch-agent/bin/
vi config.json
nginx、sshd、mysqld プロセスを監視する設定ファイル例は次の通りです。
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "cwagent"
},
"metrics": {
"metrics_collected": {
"procstat": [
{
"pattern": "nginx",
"measurement": [
"pid_count"
],
"metrics_collection_interval": 60
},
{
"pattern": "sshd",
"measurement": [
"pid_count"
],
"metrics_collection_interval": 60
},
{
"pattern": "mysqld",
"measurement": [
"pid_count"
],
"metrics_collection_interval": 60
}
]
},
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
}
}
}
設定ファイルの反映を行います。
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
CloudWatch のカスタム名前空間 CWAgent で procstat_lookup_pid_count メトリクスが確認できることを確認します。
4.CloudWatch アラームの設定
次のようなアラーム設定を行います
- メトリクス名:procstat_lookup_pid_count
- InstanceId:対象 EC2 インスタンス ID
- pattern:監視プロセス名
- 統計:最小
- 期間:1分
プロセスダウンをアラート条件としたいため、プロセス数が 0 以下としたしきい値を設定します。
- しきい値:procstat_lookup_pid_count <= 0
監視したいプロセスごとにアラームを設定します。
今回 nginx、sshd、mysqld プロセスをモニタリングする例として、アラームはそれぞれ次の名前で設定しました。
・WebServerProcessMonitor-nginx
・WebServerProcessMonitor-sshd
・WebServerProcessMonitor-mysqld
5.EventBridge ルールの設定
EventBridge ルールの作成を行います。
任意の名前を入力し、ルールタイプではイベントパターンを持つルールを選択します。
イベントパターンのフィールドに次の値を入力します。
CloudWatch アラーム の arn はご自身の環境のものに修正してください。
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"detail": {
"state": {
"value": ["ALARM"]
}
},
"resources": [
"arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-nginx",
"arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-sshd",
"arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXX:alarm:WebServerProcessMonitor-mysqld"
]
}
ターゲットタイプでは AWS のサービスを選択します。
Systems Manager オートメーションを選択し、ドキュメントでは作成済みのドキュメント名を選択します。
自動化パラメータ設定では入力トランスフォーマを選択します。
入力パス、テンプレートは次のように設定を行います。
- 入力パス
{
"InstanceId": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId",
"pattern": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.pattern"
}
- テンプレート
{
"pattern": ["<pattern>"],
"InstanceId":["<InstanceId>"]
}
実行ロールは既存のロールにチェックを入れ、作成した EventBridge イベント用オートメーション実行ロール名を選択します。
以上で設定は完了です。
やってみた
プロセスを停止して自動復旧の動作検証をやってみます。
監視対象のプロセスをそれぞれ停止してみます。
sudo systemctl stop nginx
sudo systemctl stop sshd
sudo systemctl stop mysqld
サービス停止によりプロセス数がしきい値を下回ります。
しばらくすると CloudWatch アラームがアラート状態に変化します。
アラート変化のイベントが発生することで EventBridge ルールによりターゲットであるオートメーションが実行されました。
AWS-RunShellScript によりサービス起動の自動復旧処理が行われます。
自動復旧処理によりサービスが開始されるため、プロセス数がしきい値を上回ります。
しばらくすると CloudWatch アラームが OK 状態に戻ったことが確認できます。
デバック方法
EventBridge ルールを設定してみたものの、イベントが発生してもうまくオートメーションが実行されないといったケースがあるかと思います。
デバックに役立つ情報を出力する方法を紹介します。
ターゲットに CloudWatchLogs 設定する
EventBridge ターゲットは複数設定することができます。
CloudWatchLogs をターゲットを設定することで、実際に発生した CloudWatch アラームイベントの JSON を確認することができます。
JSON データと入力トランスフォーマのパスが正しいか確認することができます。
デットレターキューを設定する
未処理のイベントを SQS へ送信することができます。
あらかじめ SQS の標準キューを作成の上、デットレターキューを設定します。
何らかの理由で EventBridge ルールでターゲットの呼び出しに失敗した場合、デットレターキューにメッセージが保存されます。
メッセージからエラーコードとエラーメッセージを確認することができます。
(参考)メッセージを受信する AWS CLI コマンド例
aws sqs receive-message \
--queue-url https://sqs.ap-northeast-1.amazonaws.com/XXXXXXXXXXX/XXX \
--max-number-of-messages 10 \
--visibility-timeout 30 \
--wait-time-seconds 0 \
--attribute-names All \
--message-attribute-names All \
--output json
{
"Messages": [
{
"MessageId": "5cd169b7-2e1b-47f0-8c5a-28de9432ff0e",
"ReceiptHandle": "AQEBSDF0tE7hMvNm+WHeTedJ2IlmeMMywObJ9qudb8cu97Cd78gxVy2SjJ0NdOvLqTfDT7UG2sUtXu2mvskDMP7YeK+FBtQazc0cAlE9sxXcFXpuKms06TzxirjBxlKeNVf5USZSP2biyBOEb88XF2HSCxZ1uSddRuEzYyU7mYjJcRfCk9uJJhwgy6c/3k1AB+ThJ+JAHmr4wTZBj0XG1lU1adnGWnNZWo6VgDYbHMomk/ArAJAhqU5ScAcQruS+i0PXmxaofmSF1X6Cl+hKTOJK0hJOqn92BB3wxT81bvIioZ63EuSGKj+W9zdGLmCrtEZUoV66MS5DDiaAf5MLNLF6HJjwbicNzNCzObqaJHJ2y75g/SRrT3BQiMSnfT+0fKgOIrdZY5Rwc5DgAtwiwZdhMw==",
"MD5OfBody": "9af3633b723de6ef7ac9c2e3012ad176",
"Body": "{\n \"pattern\": [\"nginx\"],\n \"InstanceId\":[\"i-XXXXXXXXXXX\"]\n}",
"Attributes": {
"SenderId": "AIDAIVNDY5GZ7FOG4K4K2",
"ApproximateFirstReceiveTimestamp": "1728291225293",
"ApproximateReceiveCount": "4",
"SentTimestamp": "1728011221747"
},
"MD5OfMessageAttributes": "af27f0c1b7cd363a38347b74ff975a3a",
"MessageAttributes": {
"ERROR_CODE": {
"StringValue": "INVALID_PARAMETER",
"DataType": "String"
},
"ERROR_MESSAGE": {
"StringValue": "The defined assume role is unable to be assumed. (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: InvalidAutomationExecutionParametersException; Request ID: 0a022d16-7d89-46dc-9d76-1347484d4909; Proxy: null)",
"DataType": "String"
},
"RULE_ARN": {
"StringValue": "arn:aws:events:ap-northeast-1:XXXXXXXXXXX:rule/nginx-test",
"DataType": "String"
},
"TARGET_ARN": {
"StringValue": "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXX:automation-definition/linux-recovery",
"DataType": "String"
}
}
}
]
}
まとめ
EventBridge ルールで SystemsManager のオートメーションを実行させてサービスを自動復旧させる方法を紹介しました。
サービスの起動で復旧できるパターンでは障害対応の運用が楽になると思います!
systemctl コマンドでは起動できないようなプロセスは AWS-RunShellScript で起動用のスクリプトをキックして復旧させるといったことも可能です。
本記事が誰かのお役に立てれば幸いです。
参考